Permissions.php

<?php

namespace Tlf\User;

trait Permissions {

    /**
     *  I will probably want to add permission lookup to the initial user loading. For this i might need to add types to permissions. For example, I DONT want to have a list of every single blog post that a user is allowed to edit (i.e. blog posts they have created). But i DO want a list of broader permissions that they have, like 'blog:create'
     *
     * But for now (mar 6) I just want to prototype something & have it work. I'll add this pre-fetching later, probably
     *
     *
     */

    /**
     * array of roles this user is in
     * @key role_name
     * @value true, always true
     */
    public ?array $roles;

    public function all_nonrole_permissions(){
        if (!$this->is_registered())return [];
        $stmt = $this->pdo->prepare($this->queries['user.all_nonrole_permissions']);
        $stmt->execute(['user_id'=>$this->id]);
        $rows = $stmt->fetchAll(\PDO::FETCH_COLUMN);
        return $rows;
    }
    /**
     * get all role-based permissions for the user. Will not return any roles if there are no permissions added to the role
     */
    public function all_roles(){

        $sql = $this->queries['user.all_roles'];
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute(['user_id'=>$this->id]);
        $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);
        $roles = [];
        foreach ($rows as $r){
            if ($r['perm']===null&&!isset($roles[$r['role']])){
                $roles[$r['role']] = [];
                continue;
            }
            $roles[$r['role']][] = $r['perm'];
        }
        return $roles;
    }

    /**
     * Get array of all role names this user has
     */
    public function get_all_roles(){

        $sql = $this->queries['user.get_all_roles'];
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute(['user_id'=>$this->id]);
        $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);

        $roles = [];
        foreach ($rows as $r){
            $roles[$r['role']] = true;
        }
        return $roles;
    }

    /**
     * check if user has role. Roles list is cached first time this is called. If you add a role after calling this, you must re-load the user or set $user->roles = null;
     * @param $role_name the name of a role like `admin` or `moderator`
     * @return true/false
     */
    public function has_role(string $role_name): bool{
        $roles = $this->roles ?? ($this->roles = $this->get_all_roles());
        return isset($roles[$role_name]);
    }

    /**
     * add a role to this user
     */
    public function add_role(string $role){
        if (!$this->is_registered())return false;
        $stmt = $this->pdo->prepare($this->queries['user.add_role']);
        $stmt->execute(['role'=>$role, 'user_id'=>$this->id]);
    }
    /**
     * remove a role to this user
     */
    public function remove_role(string $role){
        if (!$this->is_registered())return false;
        $stmt = $this->pdo->prepare($this->queries['user.remove_role']);
        $stmt->execute(['role'=>$role, 'user_id'=>$this->id]);
    }

    /**
     * @param $action name of an action the user can do
     * @return false if we could not enable the user to take $action
     */
    public function allow(string $action){
        if (!$this->is_registered())return false;
        $stmt = $this->pdo->prepare($this->queries['user.allow']);
        $stmt->execute(['action'=>$action, 'user_id'=>$this->id]);

        // print_r($this->pdo->errorInfo());
    }

    public function deny(string $action){
        if (!$this->is_registered())return false;
        $stmt = $this->pdo->prepare($this->queries['user.deny']);
        $stmt->execute([
            'action'=>$action,
            'user_id'=>$this->id
        ]);

        if ($stmt->rowCount()==1)return true;

        return false;
    }
    
    /**
     * @param $action an action the user wishes to perform
     * @return true/false
     */
    public function can(string $action){
        $stmt = $this->pdo->prepare($this->queries['user.can']);

        $stmt->execute(
            ['action'=>$action, 'user_id'=>$this->id]
        );
        // print_r($this->pdo->errorInfo());
        if ($stmt->fetch()!==false){
            $stmt->closeCursor();
            unset($stmt);
            return true;
        }
        return false;
    }

}